package com.eairlv.utils.validator.url;

import cn.hutool.core.util.ReflectUtil;
import com.eairlv.utils.MSInterceptorProperties;
import com.eairlv.utils.annotation.AccessPermission;
import com.eairlv.utils.config.MSInterceptor;
import com.eairlv.utils.utils.HttpUtil;
import com.eairlv.utils.utils.LogUtil;
import com.eairlv.utils.validator.user.UserInformation;
import com.eairlv.utils.validator.user.UserValidator;
import io.undertow.server.HttpServerExchange;
import io.undertow.servlet.spec.HttpServletRequestImpl;
import io.undertow.util.HttpString;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.tomcat.util.http.MimeHeaders;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;

/**
 * @author eairlv
 * @description
 * @date 11:26 2019/8/27
 */
@Slf4j
public class UrlValidator {

    /**
     * undertow容器
     */
    public static final String UNDERTOW = "io.undertow.servlet.spec.HttpServletRequestImpl";

    /**
     * tomcat容器
     */
    public static final String TOMCAT = "org.apache.catalina.connector.RequestFacade";

    /**
     * 用户身份标识
     */
    public static final String GATEWAY_AUTHORIZATION = "Gateway-Authorization";

    /**
     * URL权限验证器
     *
     * @param request
     * @param restTemplate
     * @param properties
     * @return
     */
    public static Boolean valid(HttpServletRequest request, RestTemplate restTemplate, MSInterceptorProperties properties, HandlerMethod handler) {
        AccessPermission accessPermission = getEffectiveAnnotation(handler);
        if (null != accessPermission) {
            if (!accessPermission.jwt()) {
                /**
                 * jwt=false不校验权限
                 */
                return Boolean.TRUE;
            }

            /**
             * 需要校验
             */
            String token = request.getHeader(GATEWAY_AUTHORIZATION);
            if (null == token || token.length() == 0) {
                /**
                 * token为空，直接失败
                 */
                return Boolean.FALSE;
            }

            /**
             * 校验token
             */
            UserInformation userInformation = UrlClient.jwt(request.getMethod(), request.getRequestURI(), token, restTemplate, properties);
            if (userInformation != null) {
                if (userInformation.getId() != null) {
                    if (properties.getUserPayload().equals(UserValidator.HEADER)) {
                        try {
                            if (Class.forName(UNDERTOW) != null && request instanceof HttpServletRequestImpl) {
                                ((HttpServerExchange) ReflectUtil.getFieldValue(request, "exchange"))
                                        .getRequestHeaders().add(new HttpString(UserValidator.USER_INFORMATION), HttpUtil.writeUserInfoToHeaderString(userInformation));
                            }
                        } catch (Exception e) {
                            log.warn("undertow container error", LogUtil.getExceptionMessage(e));
                        }
                        try {
                            if (Class.forName(TOMCAT) != null && request instanceof RequestFacade) {
                                Request req = (Request) ReflectUtil.getFieldValue(request, "request");
                                org.apache.coyote.Request creq = (org.apache.coyote.Request) ReflectUtil.getFieldValue(req, "coyoteRequest");
                                MimeHeaders headers = (MimeHeaders) ReflectUtil.getFieldValue(creq, "headers");
                                headers.addValue(UserValidator.USER_INFORMATION).setString(HttpUtil.writeUserInfoToHeaderString(userInformation));
                            }
                        } catch (Exception e) {
                            log.warn("tomcat container error", LogUtil.getExceptionMessage(e));
                        }
                    } else {
                        MSInterceptor.USER_INFORMATION.set(userInformation);
                    }
                }
                return Boolean.TRUE;
            } else {
                return Boolean.FALSE;
            }
        } else {
            return Boolean.TRUE;
        }
    }

    private static AccessPermission getEffectiveAnnotation(HandlerMethod handler) {
        AccessPermission classAnnotation = handler.getClass().getAnnotation(AccessPermission.class);
        AccessPermission methodAnnotation = handler.getMethodAnnotation(AccessPermission.class);
        if (null != methodAnnotation) {
            return methodAnnotation;
        } else if (null != classAnnotation) {
            return classAnnotation;
        } else {
            return null;
        }
    }
}
